#pragma once
#pragma warning (disable : 4248)

#include <ode/ode.h>
#include "DIUnmanagedPointer.h"

using namespace System;
using namespace System::Runtime::InteropServices;
using namespace System::Collections::Generic;

#define STRINGTO_CONSTCHAR_ANSI(ptrName,value) IntPtr _##ptrName## = Marshal::StringToHGlobalAnsi(value);\
const char* ptrName = static_cast<const char*>(_##ptrName##.ToPointer());

#define STRINGTOCHAR_ANSI(ptrName,value) IntPtr _##ptrName## = Marshal::StringToHGlobalAnsi(value);\
char* ptrName = static_cast<char*>(_##ptrName##.ToPointer());

#define FREECHARPOINTER(ptrName) System::Runtime::InteropServices::Marshal::FreeHGlobal(IntPtr((void*)ptrName));

#define INTERNAL_CLASS_DECLARATION(Class,NativeClass)\
	internal: bool _Free; bool _Disposed; NativeClass* _This;\
	void _SetPointer(NativeClass* instance , bool free){\
	_This = instance;_Free = free;_Disposed = false;}\
	Class(NativeClass* instance){_SetPointer(instance,false);}\
	protected: virtual void CollectManagedMemory();\
	public:\
	virtual property bool Disposed {bool get(){return _Disposed;}}\
	~Class(){if(!_Disposed)CollectManagedMemory();this->!Class();}\
	!Class(){if(_Free && _This)delete[] _This;_This = nullptr;_Free = false;_Disposed = true;}

#define INTERNAL_CLASS_DECLARATION_NO_FINALIZE(Class,NativeClass)\
	internal: bool _Free; bool _Disposed; NativeClass* _This;\
	void _SetPointer(NativeClass* instance , bool free){\
	_This = instance;_Free = free;_Disposed = false;}\
	Class(NativeClass* instance){_SetPointer(instance,false);}\
	protected: virtual void CollectManagedMemory();\
	public:\
	virtual property bool Disposed {bool get(){return _Disposed;}}\
	~Class(){if(!_Disposed)CollectManagedMemory();this->!Class();}

#define INTERNAL_CLASS_DECLARATION_WITH_REGISTER(Class,NativeClass)\
	internal: bool _Free; bool _Disposed; NativeClass* _This;\
	void _SetPointer(NativeClass* instance , bool free){\
	_This = instance;_Free = free;_Disposed = false;if(instance && free)DRegisteredObjects::Add(this);}\
	Class(NativeClass* instance,bool free){_SetPointer(instance,free);}\
	protected: virtual void CollectManagedMemory();\
	public:\
	virtual property bool Disposed {bool get(){return _Disposed;}}\
	~Class(){if(!_Disposed){if(_Free)DRegisteredObjects::Remove(this);CollectManagedMemory();}this->!Class();}\
	!Class(){if(_Free && _This)delete _This;_This = nullptr;_Free = false;_Disposed = true;}

#define INTERNAL_CLASS_DECLARATION_WITH_REGISTER_NO_FINALIZE(Class,NativeClass)\
	internal: bool _Free; bool _Disposed; NativeClass* _This;\
	void _SetPointer(NativeClass* instance , bool free){\
	_This = instance;_Free = free;_Disposed = false;if(instance && free)DRegisteredObjects::Add(this);}\
	Class(NativeClass* instance,bool free){_SetPointer(instance,free);}\
	protected: virtual void CollectManagedMemory();\
	public:\
	virtual property bool Disposed {bool get(){return _Disposed;}}\
	~Class(){if(!_Disposed){if(_Free)DRegisteredObjects::Remove(this);CollectManagedMemory();}this->!Class();}

#define VALUE_PROP_DECLARATION_GET(Type,Name)\
	property Type Name { Type get(); }

#define VALUE_PROP_DECLARATION_GETSET(Type,Name)\
	property Type Name { Type get(); void set(Type value); }

#define VALUE_PROP_DEFINITION_GET(Class,Value,Type,Name)\
	Type Class::Name::get(){ return Value; }

#define VALUE_PROP_DEFINITION_SET(Class,Value,Type,Name)\
	void Class::Name::set(Type value){ Value = value;}

#define VALUE_PROP_DEFINITION_GETSET(Class,Value,Type,Name)\
	VALUE_PROP_DEFINITION_GET(Class,Value,Type,Name);\
	VALUE_PROP_DEFINITION_SET(Class,Value,Type,Name);

#define REF_PROP_DECLARATION_GET(Type,Name)\
		property Type^ Name {Type^ get();}\
		internal: Type^ _##Name; public:

#define REF_PROP_DECLARATION_GETSET(Type,Name)\
		property Type^ Name {Type^ get(); void set(Type^ value);}\
		internal: Type^ _##Name; public:


#define REF_PROP_DEFINITION_GET_FROM_REF(Class,NativeValue,Type,Name)\
	Type^ Class::Name::get(){\
	if(_##Name) _##Name->_SetPointer(_This->NativeValue,false);\
	else _##Name = gcnew Type(_This->NativeValue); return _##Name;}

#define REF_PROP_DEFINITION_GET_FROM_VALUE(Class,NativeValue,Type,Name)\
	Type^ Class::Name::get(){\
	if(_##Name) _##Name->_SetPointer(&_This->NativeValue,false);\
	else _##Name = gcnew Type(&_This->NativeValue); return _##Name;}
	